(function () {
	var imp;
	importer();

	panda.render = function(partial, file, func) {
		if (typeof partial === "string") {
			func = file;
			file = partial;
			partial = false;
		}

		file = panda.render.prefix + file + ".html";

		if (func === undefined) {
			var src = imp.File(file);
			var os = imp.ByteArrayOutputStream();
			imp.Files.copy(src.toPath(), os);

			return os.toString() + "";
		}

		var parser = imp.DOMParser();	
		parser.parse(file);	
		var window = {
			document : parser.getDocument(),
			cache : imp.HashMap()
		};

		panda.jquery(window);	
		panda.tmpl(window);
		func(window.jQuery);

		var doc = window.document.documentElement;
		return partial ?
			panda.html(doc.lastChild) :
			panda.outerHtml(doc, true);
	};

	extend();

	function importer() {
		imp = JavaImporter(
			java.io,
			java.util,
			java.nio.file,
			org.w3c.dom,
			org.xml.sax,
			org.apache.html.dom,
			org.apache.xerces.dom,
			org.apache.xml.serialize,
			org.cyberneko.html.parsers);
	}

	function extend() {
		panda.outerHtml = outerHtml;
		panda.html = html;
		panda.childNodes = childNodes;		
		var r = config.render;
		panda.render.prefix = r && r.prefix || "";
	}

	function outerHtml(elem, withDocType) {
		var text = elem.nodeValue;
		if (text != null) { return text; }
	
		var out = imp.StringWriter();
	
		var f = imp.OutputFormat(elem.ownerDocument);
		f.nonEscapingElements = ["SCRIPT"];
		f.omitXMLDeclaration = true;
		f.omitDocumentType = !withDocType;
	
		imp.XMLSerializer(out, f).serialize(elem);
		return out.toString() + "";
	}
	
	function html(elem, html) {
		if (html === undefined) {		
			var ret = "";
			for (var i = 0, l = elem.length; i < l; ++i) {
				ret += panda.outerHtml(elem.item(i));
			}
			return ret;
		}
		
		var fragment = elem.ownerDocument.createDocumentFragment();
		var parser = imp.DOMFragmentParser();
		var reader = imp.StringReader(html);
		parser.parse(imp.InputSource(reader), fragment);
	
		var child;
		while (child = elem.firstChild) {
			elem.removeChild(child);
		}
		while (child = fragment.firstChild) {
			elem.appendChild(child);
		}
	}
	
	function childNodes(elem) {
		var ret = [];
		for (var i = 0, l = elem.length; i < l; ++i) {
			ret.push(elem.item(i));
		}
		return ret;
	}
}());
